/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 *
 * @format
 */

"use strict";
var _extends =
  Object.assign ||
  function(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];
      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }
    return target;
  };
let runMetro = (() => {
  var _ref = _asyncToGenerator(function*(config) {
    const defaultConfig = yield getDefaultConfig(config.projectRoot);
    const mergedConfig = mergeConfig(defaultConfig, config);

    mergedConfig.reporter.update({
      type: "initialize_started",
      port: mergedConfig.server.port,
      // FIXME: We need to change that to watchFolders. It will be a
      // breaking since it affects custom reporter API.
      projectRoots: mergedConfig.watchFolders
    });

    return new MetroServer(mergedConfig);
  });
  return function runMetro(_x) {
    return _ref.apply(this, arguments);
  };
})();
function _asyncToGenerator(fn) {
  return function() {
    var gen = fn.apply(this, arguments);
    return new Promise(function(resolve, reject) {
      function step(key, arg) {
        try {
          var info = gen[key](arg);
          var value = info.value;
        } catch (error) {
          reject(error);
          return;
        }
        if (info.done) {
          resolve(value);
        } else {
          return Promise.resolve(value).then(
            function(value) {
              step("next", value);
            },
            function(err) {
              step("throw", err);
            }
          );
        }
      }
      return step("next");
    });
  };
}
const MetroHmrServer = require("./HmrServer");
const MetroServer = require("./Server");
const attachWebsocketServer = require("./lib/attachWebsocketServer");
const http = require("http");
const https = require("https");
const makeBuildCommand = require("./commands/build");
const makeServeCommand = require("./commands/serve");
const outputBundle = require("./shared/output/bundle");
var _require = require("fs-extra");
const readFile = _require.readFile;
var _require2 = require("metro-config");
const loadConfig = _require2.loadConfig,
  mergeConfig = _require2.mergeConfig,
  getDefaultConfig = _require2.getDefaultConfig;

exports.runMetro = runMetro;
exports.loadConfig = loadConfig;

exports.createConnectMiddleware = (() => {
  var _ref2 = _asyncToGenerator(function*(config) {
    const metroServer = yield runMetro(config);

    let enhancedMiddleware = metroServer.processRequest;

    // Enhance the resulting middleware using the config options
    if (config.server.enhanceMiddleware) {
      enhancedMiddleware = config.server.enhanceMiddleware(
        enhancedMiddleware,
        metroServer
      );
    }

    return {
      attachHmrServer(httpServer) {
        attachWebsocketServer({
          httpServer,
          path: "/hot",
          websocketServer: new MetroHmrServer(metroServer, config)
        });
      },
      metroServer,
      middleware: enhancedMiddleware,
      end() {
        metroServer.end();
      }
    };
  });
  return function(_x2) {
    return _ref2.apply(this, arguments);
  };
})();

exports.runServer = (() => {
  var _ref3 = _asyncToGenerator(function*(config, _ref4) {
    let host = _ref4.host,
      onReady = _ref4.onReady,
      onError = _ref4.onError;
    var _ref4$secure = _ref4.secure;
    let secure = _ref4$secure === undefined ? false : _ref4$secure,
      secureKey = _ref4.secureKey,
      secureCert = _ref4.secureCert;
    var _ref4$hmrEnabled = _ref4.hmrEnabled;
    let hmrEnabled = _ref4$hmrEnabled === undefined ? false : _ref4$hmrEnabled;
    // Lazy require
    const connect = require("connect");

    const serverApp = connect();
    var _ref5 = yield exports.createConnectMiddleware(config);
    const attachHmrServer = _ref5.attachHmrServer,
      middleware = _ref5.middleware,
      metroServer = _ref5.metroServer,
      end = _ref5.end;

    serverApp.use(middleware);

    if (config.server.enableVisualizer) {
      let initializeVisualizerMiddleware;
      try {
        var _require3 = require("metro-visualizer"); // eslint-disable-next-line import/no-extraneous-dependencies
        // $FlowExpectedError
        initializeVisualizerMiddleware =
          _require3.initializeVisualizerMiddleware;
      } catch (e) {
        console.warn(
          "'config.server.enableVisualizer' is enabled but the 'metro-visualizer' package was not found - have you installed it?"
        );
      }
      if (initializeVisualizerMiddleware) {
        serverApp.use(
          "/visualizer",
          initializeVisualizerMiddleware(metroServer)
        );
      }
    }

    let httpServer;

    if (secure) {
      httpServer = https.createServer(
        {
          key: yield readFile(secureKey),
          cert: yield readFile(secureCert)
        },

        serverApp
      );
    } else {
      httpServer = http.createServer(serverApp);
    }

    httpServer.on("error", function(error) {
      onError && onError(error);
      end();
    });

    if (hmrEnabled) {
      attachHmrServer(httpServer);
    }

    return new Promise(function(resolve, reject) {
      httpServer.listen(config.server.port, host, function() {
        onReady && onReady(httpServer);
        resolve(httpServer);
      });

      // Disable any kind of automatic timeout behavior for incoming
      // requests in case it takes the packager more than the default
      // timeout of 120 seconds to respond to a request.
      httpServer.timeout = 0;

      httpServer.on("error", function(error) {
        end();
        reject(error);
      });

      httpServer.on("close", function() {
        end();
      });
    });
  });
  return function(_x3, _x4) {
    return _ref3.apply(this, arguments);
  };
})();

exports.runBuild = (() => {
  var _ref6 = _asyncToGenerator(function*(config, _ref7) {
    var _ref7$dev = _ref7.dev;
    let dev = _ref7$dev === undefined ? false : _ref7$dev,
      entry = _ref7.entry,
      onBegin = _ref7.onBegin,
      onComplete = _ref7.onComplete,
      onProgress = _ref7.onProgress;
    var _ref7$minify = _ref7.minify;
    let minify = _ref7$minify === undefined ? true : _ref7$minify;
    var _ref7$output = _ref7.output;
    let output = _ref7$output === undefined ? outputBundle : _ref7$output,
      out = _ref7.out;
    var _ref7$platform = _ref7.platform;
    let platform = _ref7$platform === undefined ? "web" : _ref7$platform;
    var _ref7$sourceMap = _ref7.sourceMap;
    let sourceMap = _ref7$sourceMap === undefined ? false : _ref7$sourceMap,
      sourceMapUrl = _ref7.sourceMapUrl;
    const metroServer = yield runMetro(config);

    try {
      const requestOptions = {
        dev,
        entryFile: entry,
        inlineSourceMap: sourceMap && !sourceMapUrl,
        minify,
        platform,
        sourceMapUrl: sourceMap === false ? undefined : sourceMapUrl,
        createModuleIdFactory: config.serializer.createModuleIdFactory,
        onProgress
      };

      if (onBegin) {
        onBegin();
      }

      const metroBundle = yield output.build(metroServer, requestOptions);

      if (onComplete) {
        onComplete();
      }

      if (out) {
        const bundleOutput = out.replace(/(\.js)?$/, ".js");
        const sourcemapOutput =
          sourceMap === false ? undefined : out.replace(/(\.js)?$/, ".map");

        const outputOptions = {
          bundleOutput,
          sourcemapOutput,
          dev,
          platform
        };

        // eslint-disable-next-line no-console
        yield output.save(metroBundle, outputOptions, console.log);
      }

      return metroBundle;
    } finally {
      yield metroServer.end();
    }
  });
  return function(_x5, _x6) {
    return _ref6.apply(this, arguments);
  };
})();

exports.buildGraph = (() => {
  var _ref8 = _asyncToGenerator(function*(config, _ref9) {
    var _ref9$customTransform = _ref9.customTransformOptions;
    let customTransformOptions =
      _ref9$customTransform === undefined
        ? Object.create(null)
        : _ref9$customTransform;
    var _ref9$dev = _ref9.dev;
    let dev = _ref9$dev === undefined ? false : _ref9$dev,
      entries = _ref9.entries;
    var _ref9$minify = _ref9.minify;
    let minify = _ref9$minify === undefined ? false : _ref9$minify,
      onProgress = _ref9.onProgress;
    var _ref9$platform = _ref9.platform;
    let platform = _ref9$platform === undefined ? "web" : _ref9$platform;
    var _ref9$type = _ref9.type;
    let type = _ref9$type === undefined ? "module" : _ref9$type;
    const metroServer = yield runMetro(config);

    try {
      return yield metroServer.buildGraph(
        entries,
        _extends({}, MetroServer.DEFAULT_GRAPH_OPTIONS, {
          customTransformOptions,
          dev,
          minify,
          platform,
          type
        })
      );
    } finally {
      yield metroServer.end();
    }
  });
  return function(_x7, _x8) {
    return _ref8.apply(this, arguments);
  };
})();

exports.attachMetroCli = function(yargs) {
  var _ref10 =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
    _ref10$build = _ref10.build;
  let build = _ref10$build === undefined ? {} : _ref10$build;
  var _ref10$serve = _ref10.serve;
  let serve = _ref10$serve === undefined ? {} : _ref10$serve;
  if (build) {
    var _makeBuildCommand = makeBuildCommand();
    const command = _makeBuildCommand.command,
      description = _makeBuildCommand.description,
      builder = _makeBuildCommand.builder,
      handler = _makeBuildCommand.handler;
    yargs.command(command, description, builder, handler);
  }
  if (serve) {
    var _makeServeCommand = makeServeCommand();
    const command = _makeServeCommand.command,
      description = _makeServeCommand.description,
      builder = _makeServeCommand.builder,
      handler = _makeServeCommand.handler;
    yargs.command(command, description, builder, handler);
  }
  return yargs;
};

// The symbols below belong to the legacy API and should not be relied upon
Object.assign(exports, require("./legacy"));
